import axios from "axios";
import { AxiosCanceler } from "@/utils/http/axiosCanceler";
import { cloneDeep, isFunction } from "lodash-es";

export class VAxios {
  constructor(options) {
    this.options = options;
    this.axiosInstance = axios.create(options);

    // 初始化拦截器
    this.setupInterceptors();
  }

  /** 拦截器配置 */
  setupInterceptors() {
    const {
      axiosInstance,
      options: { transform },
    } = this;

    /** 无数据转换时认为请求异常 */
    if (!transform) return;

    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;

    // 创建一个取消器
    const axiosCanceler = new AxiosCanceler();

    // 设定请求拦截器
    this.axiosInstance.interceptors.request.use((config) => {
      const requestOptions =
        config.requestOptions || this.options.requestOptions;

      // 判断是否需要 添加取消请求控制
      const ignoreCancelToken = requestOptions.ignoreCancelToken || true;
      // 如果需要添加取消请求控制 向取消Map中追加当前请求
      !ignoreCancelToken && axiosCanceler.addPending(config);

      if (requestInterceptors && isFunction(requestInterceptors)) {
        config = requestInterceptors(config, this.options);
      }

      return config;
    }, undefined);
    // 检测是否需要 异常捕获
    requestInterceptorsCatch &&
      isFunction(requestInterceptorsCatch) &&
      this.axiosInstance.interceptors.request.use(
        undefined,
        requestInterceptorsCatch
      );

    // 设定响应拦截器
    this.axiosInstance.interceptors.response.use((response) => {
      /** 响应结果出现代表请求结束，需要移除当前已完成请求 */
      response && axiosCanceler.removePending(response.config);
      if (responseInterceptors && isFunction(responseInterceptors)) {
        result = responseInterceptors(response);
      }
      return result;
    }, undefined);

    // 检测是否需要 异常捕获
    responseInterceptorsCatch &&
      isFunction(responseInterceptorsCatch) &&
      this.axiosInstance.interceptors.response.use(undefined, (error) => {
        /** 处理异常: 此处传入axios实例方便重播 */
        return responseInterceptorsCatch(axiosInstance, error);
      });
  }

  get(config, options = {}) {
    return this.request({ ...config, method: "GET" }, options);
  }

  post(config, options = {}) {
    return this.request({ ...config, method: "POST" }, options);
  }

  put(config, options = {}) {
    return this.request({ ...config, method: "PUT" }, options);
  }

  delete(config, options = {}) {
    return this.request({ ...config, method: "DELETE" }, options);
  }

  request(config, options = {}) {
    let conf = cloneDeep(config);
    // 深拷贝导致 外层无法使用cancel方法来取消请求
    if (config.cancelToken) {
      conf.cancelToken = config.cancelToken;
    }
    if (config.signal) {
      conf.signal = config.signal;
    }

    const transform = this.getTransform();

    const { requestOptions } = this.options;

    /** 展平操作，将配置与 options合并到一起  */
    const opt = Object.assign({}, requestOptions, options);

    const { beforeRequestHook, requestCatchHook, transformResponseHook } =
      transform || {};

    if (beforeRequestHook && isFunction(beforeRequestHook)) {
      // 数据处理config
      conf = beforeRequestHook(conf, opt);
    }

    // 重新将 requestOptions 创建到 config中，此处直接用 现有options替换掉默认的requestOptions
    conf.requestOptions = opt;

    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request(conf)
        .then((res) => {
          if (transformResponseHook && isFunction(transformResponseHook)) {
            try {
              const ret = transformResponseHook(res, opt);
              resolve(ret);
            } catch (err) {
              reject(err || new Error("request error!"));
            }
            return;
          }
          resolve(res);
        })
        .catch((err) => {
          if (requestCatchHook && isFunction(requestCatchHook)) {
            reject(requestCatchHook(err, opt));
            return;
          }
          if (axios.isAxiosError(err)) {
            // rewrite error message from axios in here
          }
          reject(err);
        });
    });
  }
}
